home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
calc.arc
/
CALC.C
next >
Wrap
C/C++ Source or Header
|
1985-11-24
|
19KB
|
602 lines
/*
* CALC.C
*
* Author: R. E. Sawyer
*
* Date: 16 Nov 85
*
* Language: C (DeSmet V2.4)
*
* Description: CALC is an interactive RPN-style calculator. Each line of
* instructions entered at the keyboard is immediately interp-
* reted, and CALC may also be directed to save each line in a
* journal file for later re-play. Such a file may also be
* created by previous use of a text editor.
*/
#include <math.h>
#include <stdio.h>
#define MAXLINE 80
#define MAXWORD 20
#define MAXSTACK 100
#define MAXMEM 100
#define MAXKEY 100
#define MAXVAR 100
#define MAXVLEN 6
#define TAB " "
FILE *fin = 0;
FILE *fout = 0;
int isfromfile = 0;
int istofile = 0;
static char vname[MAXVAR][MAXVLEN] = {"\0"};
static double val[MAXVAR] = {0.0};
int vnum = 0;
int sp = 0;
double stack[MAXSTACK+1];
double mem[MAXMEM+1];
extern double atof();
static char *keyword[] = {
"HELP display this summary",
"QUIT exit CALC",
"nnn append s0 = any number nnn",
"abc append s0 = value of variable abc",
"=abc store s0 as variable abc, delete s0",
"= display s0",
"+ s0 <-- s1 + s0, delete s1",
"- s0 <-- s1 - s0, delete s1",
"* s0 <-- s1 * s0, delete s1",
"/ s0 <-- s1 / s0, delete s1",
"^ s0 <-- s1 to the power s0, delete s1",
"?< s0 <-- 1(0) if s1 < (>=) s0, delete s1",
"?<= s0 <-- 1(0) if s1 <= (>) s0, delete s1",
"?= s0 <-- 1(0) if s1 = (<>) s0, delete s1",
"ABS s0 <-- absolute value of s0",
"ACOS s0 <-- arccosine of s0",
"ASIN s0 <-- arcsine of s0",
"ATAN s0 <-- arctangent of s0",
"CEIL s0 <-- least integer not less than s0",
"CHS s0 <-- -s0",
"COS s0 <-- cosine of s0",
"COSH s0 <-- hyperbolic cosine of s0",
"EXP s0 <-- e to the power s0",
"EXP10 s0 <-- 10 to the power s0",
"FLOOR s0 <-- greatest integer not greater than s0",
"INV s0 <-- 1 / s0",
"LOG s0 <-- base e logarithm of s0",
"LOG10 s0 <-- base 10 logarithm of s0",
"MAX s0 <-- maximum of s0 & s1, delete s1",
"MIN s0 <-- minimum of s0 & s1, delete s1",
"MOD s0 <-- s1 modulo s0, delete s1",
"PSE pause until any key is typed (and ignored)",
"PI append s0 = 3.14159...",
"SIN s0 <-- sine of s0",
"SINH s0 <-- hyperbolic sine of s0",
"SQR s0 <-- s0 * s0",
"SQRT s0 <-- square root of s0",
"TAN s0 <-- tangent of s0",
"TANH s0 <-- hyperbolic tangent of s0",
"CL0 delete s0",
"CLA delete stack & variables, zero all registers",
"CLM zero all registers",
"CLS delete stack",
"CLV delete all variables",
"RCL append s0 = register s0",
"SHO display stack",
"XCH exchange s0,s1",
"STO store s1 in register s0, delete s0",
"STO+ add s1 to register s0, delete s0",
"STO- subtract s1 from register s0, delete s0",
"STO* multiply register s0 by s1, delete s0",
"STO/ divide register s0 by s1, delete s0",
"<<abc execute instructions in file abc",
">>abc begin saving instructions to file abc",
">> stop saving instructions to file"
};
main()
{
int i, j;
char line[MAXLINE+1];
char word[MAXWORD+1];
int start;
int iop1;
double op1, op2;
double push(), pop();
FILE *opener();
header();
while (TRUE)
{
start = 0;
if (!isfromfile)
printf("CALC> ");
getline(line);
if (istofile && !(line[0] == '>' && line[1] == '>'))
{
fputs(line,fout);
fputs("\n",fout);
}
if (isfromfile)
printf("%s",line);
while (getword(word, line, &start))
{
if (word[0] == '<' && word[1] == '<')
{
fin = opener(word+2,0);
isfromfile = fin;
break;
}
if (word[0] == '>' && word[1] == '>')
{
if (istofile)
{
fclose(fout);
istofile = 0;
}
else if (!isfromfile)
{
fout = opener(word+2,1);
istofile = fout;
break;
}
}
else if (word[0] == '=' && isalpha(word[1]))
if (sp > 0)
if ( (i=search(vname,word+1)) >= 0 )
val[i] = pop();
else
if (vnum <= MAXVAR)
{
strcpy(vname+vnum, word+1);
val[vnum] = pop();
++vnum;
}
else
printf("%sNo room for %s.\n",TAB,word+1);
else
printf("%sNothing to store in %s.\n",TAB,word+1);
else if (isdigit(word[0]) || word[0] == '.')
push(atof(word));
else if (word[0] == '-' && (isdigit(word[1]) || word[1] == '.'))
push(-atof(word+1));
else if (is(word,"CL0"))
if (sp > 0)
pop();
else
printf("%sNothing to clear.\n",TAB);
else if (is(word,"STO"))
if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
mem[iop1] = push(pop());
else
{
printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
break;
}
else if (is(word,"STO+"))
if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
mem[iop1] += push(pop());
else
{
printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
break;
}
else if (is(word,"STO-"))
if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
mem[iop1] -= push(pop());
else
{
printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
break;
}
else if (is(word,"STO*"))
if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
mem[iop1] *= push(pop());
else
{
printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
break;
}
else if (is(word,"STO/"))
if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
mem[iop1] /= push(pop());
else
{
printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
break;
}
else if (is(word,"RCL"))
if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
push(mem[iop1]);
else
{
printf("%sMust have 0<=M<=%3.0d in M RCL.\n",TAB,MAXMEM);
break;
}
else if (is(word,"+"))
push(pop() + pop());
else if (is(word,"*"))
push(pop() * pop());
else if (is(word,"-"))
{
op2 = pop();
push(pop() - op2);
}
else if (is(word,"/"))
{
op2 = pop();
if (op2 != 0.0)
push(pop() / op2);
else
{
printf("%sAttempted division by zero.\n",TAB);
break;
}
}
else if (is(word,"?<"))
{
op2 = pop();
push(pop() < op2 ? 1.0 : 0.0);
}
else if (is(word,"?<="))
{
op2 = pop();
push(pop() <= op2 ? 1.0 : 0.0);
}
else if (is(word,"?="))
{
op2 = pop();
push(pop() == op2 ? 1.0 : 0.0);
}
else if (is(word,"CHS"))
push(-pop());
else if (is(word,"XCH"))
{
op1 = pop();
op2 = pop();
push(op1);
push(op2);
}
else if (is(word,"INV"))
if ((op1=pop()) != 0.0)
push(1.0 / pop());
else
{
printf("%sMust have X<>0 in 1/X.\n",TAB);
break;
}
else if (is(word,"ABS"))
push(fabs(pop()));
else if (is(word,"ACOS"))
push(acos(pop()));
else if (is(word,"ASIN"))
push(asin(pop()));
else if (is(word,"ATAN"))
push(atan(pop()));
else if (is(word,"CEIL"))
push(ceil(pop()));
else if (is(word,"COS"))
push(cos(pop()));
else if (is(word,"EXP"))
push(exp(pop()));
else if (is(word,"EXP10"))
push(exp10(pop()));
else if (is(word,"FLOOR"))
push(floor(pop()));
else if (is(word,"LOG"))
if ((op1=pop()) > 0.0)
push(log(op1));
else
{
printf("%sMust have X>0 in LOG(X).\n",TAB);
break;
}
else if (is(word,"LOG10"))
if ((op1=pop()) > 0.0)
push(log10(op1));
else
{
printf("%sMust have X>0 LOG10(X).\n",TAB);
break;
}
else if (is(word,"^"))
if ((op2 = pop()) > 0.0)
push(pow(pop(), op2));
else
{
printf("%sMust have X>0 in X^Y.\n", TAB);
break;
}
else if (is(word,"SIN"))
push(sin(pop()));
else if (is(word,"SQR"))
push((op1=pop()) * op1);
else if (is(word,"SQRT"))
if ((op1=pop()) >= 0.0)
push(sqrt(op1));
else
{
printf("%sMust have X>=0 in SQRT(X).\n",TAB);
break;
}
else if (is(word,"TAN"))
push(tan(pop()));
else if (is(word,"MIN"))
{
op2 = pop();
push(((op1 = pop()) < op2) ? op1 : op2);
}
else if (is(word,"MAX"))
{
op2 = pop();
push(((op1 = pop()) > op2) ? op1 : op2);
}
else if (is(word,"SINH"))
push(0.5*(exp(op1=pop()) - exp(-op1)));
else if (is(word,"COSH"))
push(0.5*(exp(op1=pop()) + exp(-op1)));
else if (is(word,"TANH"))
{
op2 = exp(op1=pop()) - exp(-op1);
push(op2 / (exp(op1) + exp(-op1)));
}
else if (is(word,"PI"))
push(4.0*atan(1.0));
else if (is(word,"="))
if (sp > 0)
printf("%s%20.14le\n", TAB, push(pop()));
else
printf("%sStack empty.\n",TAB);
else if (is(word,"CLS"))
clearstack();
else if (is(word,"CLM"))
clearmem();
else if (is(word,"CLV"))
clearvar();
else if (is(word,"CLA"))
{
clearstack();
clearmem();
clearvar();
}
else if (is(word,"SHO"))
showstack();
else if (is(word,"HELP"))
help();
else if (is(word,"QUIT"))
exit();
else if ( (i=search(vname,word)) >= 0 )
push(val[i]);
else if (is(word,"PSE"))
{
getchar();
putchar('\b\n');
}
else
{
printf("%sUnrecognized symbol: %s\n", TAB, word);
printf("%sDo you want help? (y/n) ",TAB);
if (tolower(getchar()) == 'y')
help();
else
printf("\n");
}
}
}
}
double push(x)
double x;
{
if (sp < MAXSTACK)
{
stack[sp++] = x;
}
else
{
printf("%sStack overflow.\n", TAB);
clearstack();
}
return (x);
}
double pop()
{
double x;
if (sp > 0)
x = stack[--sp];
else
{
printf("%sValue not found -- stack may be corrupted.\n", TAB);
clearstack();
x = 0.0;
}
return (x);
}
void clearstack()
{
sp = 0;
}
void showstack()
{
int i;
if (sp == 0)
{
printf("%sStack empty.\n", TAB);
return;
}
for (i=0; i<sp-1; ++i)
printf("%s%20.14le\n", TAB, stack[i]);
printf("%s%20.14le <--TOP\n", TAB, stack[sp-1]);
}
void clearmem()
{
int i;
for (i=0; i<=MAXMEM; ++i)
mem[i] = 0;
}
void clearvar()
{
vnum = 0;
vname[0][0] = '\0';
}
void help()
{
int i;
printf("\n\n\n\n\n\n");
printf("%sCALC is an interactive RPN-style calculator with an \n",TAB);
printf("%sinstruction set resembling that of an HP calculator.\n",TAB);
printf("%sEach line of instructions entered at the keyboard is\n",TAB);
printf("%simmediately executed, and may also be automatically \n",TAB);
printf("%sjournaled in a command file. CALC can be made to read\n",TAB);
printf("%sand execute the instructions on-file at any time. A\n",TAB);
printf("%scommand file can also be created with a text editor.\n",TAB);
printf("\n%sAs in an HP calulator, instructions are interpreted\n",TAB);
printf("%sas \"Reverse Polish Notation\", and operate on values\n",TAB);
printf("%sstored on a \"stack\" -- a \"last-in first-out\" list.\n",TAB);
printf("%sThe stack is represented as (...,s2,s1,s0), where s0\n",TAB);
printf("%sis accessed first (\"top-of-stack\"), s1 is next, etc.\n",TAB);
printf("%sAll values are double precision (8-byte) floats.\n\n",TAB);
printf("%sThe following are valid symbols if separated by spaces:\n",TAB);
printf("\n\n\n\n\n\n");
more();
for (i=0; i<MAXKEY && *keyword[i] != '\0'; ++i)
{
if (i%24 == 0 && i>0)
more();
printf("%s%s\n",TAB,keyword[i]);
}
printf("\n\n");
}
more()
{
printf("-MORE-");
getchar();
printf("\b\b\b\b\b\b\b");
}
static char *q[3] = {"r","w","a"};
FILE *opener(s,t)
char *s;
int t;
{
FILE *f;
if ((f = fopen(s,q[t])) == NULL)
printf("%sCan't open %s.\n",TAB,s);
return (f);
}
/* get a line of text, from the keyboard or a file, to line[] string*/
int getline(line)
char line[];
{
if (isfromfile)
{
if (fgets(line,MAXLINE,fin) == NULL)
{
fclose(fin);
isfromfile = 0;
}
}
else
gets(line);
}
/* get word-string from line-string beginning at index=start */
/* return length of word-string */
int getword(word, line, start)
char word[];
char line[];
int *start;
{
int i, j;
for (i=*start, j=0; line[i] != '\0'; ++i)
{
if (!isop(line[i]))
;
else
{
for (j=0; j <= MAXWORD && isop(line[i]); ++j)
word[j] = toupper(line[i++]);
word[j] = '\0';
*start = i;
break;
}
}
if (j == 0)
word[0] = '\0';
if (j > MAXWORD)
{
printf("%sSymbol too long: %s", TAB, word);
for (i=*start; i<=MAXLINE && isop(line[i]); ++i)
printf("%c", toupper(line[i]));
printf("\n");
}
return (j);
}
/* return TRUE if c is in the alphabet for words */
int isop(c)
char c;
{
int i;
if (c >= '!' && c <= '~')
return (TRUE);
else
return (FALSE);
}
int is(word, str)
char word[];
char str[];
{
return (strcmp(word, str) == 0);
}
int search(var, word)
char var[][MAXVLEN];
char word[];
{
int i;
for (i=0; i <= MAXVAR && (var[i][0] != '\0'); ++i)
if (is(word,var[i]))
return (i);
return (-1);
}
void header()
{
printf("\nCALC -- R. E. Sawyer, 16 Nov 85\n\n");
}